#ifndef __DRIVER_PCNET_H
#define __DRIVER_PCNET_H

#include <arch/pci.h>

#define DRIVER_NAME "netcard-pcnet"
#define DRIVER_VER "0.1"

#define DEVICE_NAME "pcnet"

#define PCNET_VENDOR 0x1022
#define PCNET_DEVICE 0x2000

#define ETH_ALEN 6         // MAC addr
#define ETH_ZLEN 60        // minimum length of data without CRC
#define ETH_DATA_LEN 1500  // maximum length of data in a frame
#define ETH_FRAME_LEN 1518 // maximum ethernet data length

#define RX_MSG_CNT 8                    // 4 msg queue
#define RX_MSG_SIZE (ETH_FRAME_LEN + 4) // 4 sava real msg size

#define TX_CACHE_BUFF_SIZE (2048)

// io address offset map
#define PCNET_WIO_RDP 0x10   // CSR data
#define PCNET_WIO_RAP 0x14   // CSR and BSR index
#define PCNET_WIO_RESET 0x18 // reset register
#define PCNET_WIO_BDP 0x1C   // BSR data

#define CSR0 0 // AMD PCNET control and status register
#define CSR1 1 // init block address
#define CSR2 2 // init block address
#define CSR3 3 // interrupt mask and default control
#define CSR4 4 // test and features control
#define CSR5 5
#define CSR6 6   // rx/tx descriptor table length
#define CSR15 15 // mode
#define CRS18 18 // current receive buffer address lower
#define CRS19 19 // current receive buffer address upper
#define CRS24 24 // base address of receive descriptor ring lower
#define CRS25 25 // base address of receive descriptor ring upper
#define CSR30 30 // base address of transmit descriptor ring lower
#define CSR31 31 // base address of transmit descriptor ring upper
#define CSR58 58 // software style
#define CSR72 72 // receive descriptor ring counter
#define CSR74 74 // transmit descriptor ring counter

#define BCR2 2

#define CSR0_INIT 0x1
#define CSR0_START 0x2
#define CSR0_STOP 0x4
#define CSR0_TXPOLL 0x8
#define CSR0_INTEN 0x40
#define CSR0_IDON 0x100
#define CSR0_NORMA (CSR0_START | CSR0_INTEN)
#define CSR0_TINT 0x0200 // transmit interrupt
#define CSR0_RINT 0x0400 // receive interrupt
#define CSR0_MERR 0x0800 // memory error
#define CSR0_MISS 0x1000 // missed frame
#define CSR0_CERR 0x2000 // collision error
#define CSR0_BABL 0x4000 // babble is a transmit time-out error
#define CSR0_ERR 0x8000

#define CSR3_IDONM (1 << 8) // initilization done mask

#define CSR4_ASTRP_RCV (1 << 10) // auto strip receive
#define CSR4_APAD_XMT (1 << 11)  // auto pad transmit

#define CSR5_SUSPEND 0x0001 // pause

#define CSR58_PCNET_PCI_II 0x02

#define PCNET_INIT_LOW 1
#define PCNET_INIT_HIGH 2
#define PCNET_MC_FILTER 8 // broadcast filter

#define BCR2_ASEL (1 << 1)

#define PCNET_TX_BUFFERS 8
#define PCNET_RX_BUFFERS 32
#define PCNET_LOG_TX_BUFFERS 3
#define PCNET_LOG_RX_BUFFERS 5

#define PCNET_RING_DE_SIZE 16

#define PCNET_TX_RETRY 10 // tx retry counter when no avalidable descriptor entry

#define PCNET_DESCR_STATUS_OWN 0x8000 // card own the descriptro

#define PCNET_DESC_STATUS_ENP 0x0100 // end of packet indicated that this is last buffer

#define PCNET_DESC_STATUS_STP 0x0200 // start of packet indicated that this is first buffer

// rx ring descript
struct pcnet_rx_desc
{
    uint32_t base;       // buffer base address
    uint16_t buff_len;   // buffer length
    uint16_t status;     // descriptor status
    uint16_t msg_length; // message byte count
    uint16_t rpc_rcc;
    uint32_t reserved;
} __attribute__((packed));

// tx ring descriptor
struct pcnet_tx_desc
{
    uint32_t base;     // buffer base address
    uint16_t buff_len; // buffer length
    uint16_t status;   // descriptor status
    uint32_t misc;
    uint32_t reserved;
} __attribute__((packed));

// pcnet initilization block
struct pcnet_init_block
{
    uint16_t mode;
    uint16_t tlen_rlen;
    uint8_t phyaddr[6];
    uint16_t reserved;
    uint32_t filter[2];
    // receive and transmit ring base
    uint32_t rx_ring;
    uint32_t tx_ring;
} __attribute__((packed));

typedef struct __device_extension
{
    pci_dev_t *pci_dev;
    uint64_t iobase;
    uint8_t irq;
    uint32_t flags;

    uint8_t mac_addr[ETH_ALEN]; // mac address

    struct pcnet_init_block *init_block; // init block

    size_t buffer_size; // length of packet buffer
    size_t des_size;    // length of descriptor entry

    uint32_t tx_buff_count; // totol number of transmit buffers
    uint32_t rx_buff_count; // totol number of receive buffers

    uint16_t rx_len_bits;
    uint16_t tx_len_bits;

    dma_addr_t rx_ring_dma_addr;
    dma_addr_t tx_ring_dma_addr;

    dma_addr_t init_block_dma_addr;

    // pointer to next rx/tx buffers
    uint32_t rx_buff_ptr;
    uint32_t tx_buff_ptr;

    uint32_t rx_buffs; // pysical address of actual receive buffers
    uint32_t tx_buffs; // pysical address of actual transmit buffers

    struct pcnet_rx_desc *rdes; // pinter to ring buffer of receive des
    struct pcnet_tx_desc *tdes; // pointer to ring buffer of transmit des

    device_queue_t rx_queue; // receive queue
} device_extension_t;

#endif